"""
Purpose of this module is to provide tools that will:
    download the current/latest predispatch forecast from AEMO's website
    parse the downloaded file to access the contained csv structure
    retrieve the predispatch rrp for each of the regions for each interval
    plot the result on a matplotlib chart.
"""

from __future__ import with_statement
import csv
from itertools import ifilter, ifilterfalse, dropwhile
from operator import itemgetter
import datetime

import urls
import query

def isdata(line):
    "Determine if the line in NEMReport format is data."
    return line[0] == "D"

def idx(fields, field):
    """
    return the index of the requested field in the given fields
    if the field is not in fields return None.
    """
    if field not in fields: return None
    else: return fields.index(field)

def isnone(elem):
    """
    return true if the element is a None.
    """
    return lambda x: x[elem] is None

def funcmap(lst, funcs):
    """
    apply each function in a list of functions to the first argument.
    """
    return [f(lst) for f in funcs]

def ifields(itercsv, *fields):
    """
    yield only the fields from the fields list from the csv reader provided.
    in the order presented by the fields.

    assume the csv is of the form:

    "I", "header1", "header2", "header3", ...
    "D", 3030, 0.3303, 04040, 404, ...
    "D", 5030, 0.5303, 05040, 504, ...
    "I", ...

    "I" represents a header row and "D" represents data.
    need to check whilst iterating that we are still yielding "D" data
    and not the next "I" header.

    using the above as an example the user may call:
    >>> list(ifields(csvreader, "header2", "header1"))
    [[0.3303, 3030],
     [0.5303, 5030]]

    notice how the function has returned the columns in the order
    given in the arguments.
    """
    fields = list(fields)

    # first identify the column numbers for each of the fields.
    def checkheaders(line):
        "function to check if the current line contains requested headers."
        return not set(fields) <= set(line)

    # find the row that has the column headings.
    data = dropwhile(checkheaders, itercsv)
    headers = data.next()

    # generate a sequence of requested field-order and csv order.
    ordered = ((idx(fields, hdr), i) for (i, hdr) in enumerate(headers))

    # find all from the ordered sequence that wasn't a None.
    # ordered contains None when the field wasn't in requested fields.
    fieldnums = ifilterfalse(isnone(0), ordered)

    # sort the fieldnums based on the first element in the tuple. this is
    # the order requested by the user in the argument fields.
    # then generate a list of functions that get the index from the ordering
    # in the csv file. This is how we return columns in the required order.
    getfields = [itemgetter(indx) for order, indx in sorted(fieldnums)]

    # now can yield the columns requested by user.
    for line in itercsv:
        if not isdata(line):
            raise StopIteration("No more data for this section.")
        # make the return structure.
        yield funcmap(line, getfields)

def isstate(state):
    "Return a function that checks if it's input is equal to state."
    return lambda x: x[-1] == state

def todate(d):
    return datetime.datetime.strptime(d, '%Y/%m/%d %H:%M:%S')

def getcolumns(reader, state, field):
    """
    return the contents of the datetime field and contents of 'field'
    for the state specified.
    returns x and y axis data.
    """
    # all the columns for the requested state.
    state_data = filter(isstate('NSW1'),
                            ifields(reader, 'DATETIME', field, 'REGIONID'))

    # a list of date and field like this [(date, field), (date, field), ..]
    columns = list((todate(d), float(f)) for d, f, r in state_data)

    # return a list of date and field like [(date, date, ..), (field, field..)]
    return zip(*columns)

def greaterthan(target):
    def ishigher(elem):
        return elem[1] > target
    return ishigher

def find_high_price_times(dates, prices, highprice=300):
    """
    return the times for which prices exceeds highprice.
    """
    return ifilter(greaterthan(highprice), zip(dates, prices))

if __name__ == '__main__':
    z = urls.getresource('http://www.nemweb.com.au/REPORTS/CURRENT/PreDispatchIS_Reports/')
    csvfile = urls.unzip(z)
    reader = csv.reader(csvfile)
    dates, rrp = getcolumns(reader, 'NSW1', 'RRP')
    print list(find_high_price_times(dates, rrp, 50))

    query.save(dates, rrp, 'rrp_nsw')





